package com.whiteape.book.service;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.media.AudioAttributes;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;

import com.bumptech.glide.request.target.NotificationTarget;
import com.hwangjr.rxbus.RxBus;
import com.whiteape.book.R;
import com.whiteape.book.WaApp;
import com.whiteape.book.common.RxEvent;
import com.whiteape.book.core.manager.ReadSettingManager;
import com.whiteape.book.ui.activity.BookReadActivity;
import com.whiteape.book.utils.MediaManager;
import com.whiteape.book.utils.ToastUtils;

import java.util.HashMap;
import java.util.Locale;

public class VoiceService extends Service {
    private static final String TAG = VoiceService.class.getSimpleName();
    public static final String ACTION_MEDIA_BUTTON = "mediaButton";
    public static final String ACTION_START = "action_start";
    public static final String ACTION_PAUSE = "action_pause";
    public static final String ACTION_RESUME = "action_resume";
    public static final String ACTION_STOP = "action_stop";
    public static final String ACTION_CHANGE_SPEED = "action_speed";
    public static final String ACTION_EXIT = "action_exit";
    public static final String ACTION_OPEN_READ_ACTIVITY = "action_open_activity";
    private BroadcastReceiver broadcastReceiver;
    private MediaSessionCompat mediaSessionCompat;
    private AudioFocusChangeListener audioFocusChangeListener;
    private AudioFocusRequest mFocusRequest;
    private TextToSpeech mTTS;
    private AudioManager audioManager;
    private static final int notificationId = 3222;
    private boolean pause = false;
    private boolean speak = false;
    private boolean isAudio = false;
    private boolean ttsInitedSuccess = false;
    private static boolean running = false;
    private String text;
    private String chapter;
    private String title;
    private static final long MEDIA_SESSION_ACTIONS = PlaybackStateCompat.ACTION_PLAY
            | PlaybackStateCompat.ACTION_PAUSE
            | PlaybackStateCompat.ACTION_PLAY_PAUSE
            | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
            | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
            | PlaybackStateCompat.ACTION_STOP
            | PlaybackStateCompat.ACTION_SEEK_TO;

    @Override
    public void onCreate() {
        super.onCreate();
        running = true;
        audioFocusChangeListener = new AudioFocusChangeListener();
        RxBus.get().register(this);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            initFocusRequest();
        }
        initMediaSession();
        initBroadcastReceiver();
        mediaSessionCompat.setActive(true);
        audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        updateNotification();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            String action = intent.getAction();
            if (action != null) {
                switch (action) {
                    case ACTION_PAUSE:
                        pauseVoice(true);
                        break;
                    case ACTION_RESUME:
                        resumeVoice();
                        break;
                    case ACTION_START:
                        this.text = intent.getStringExtra("text");
                        this.chapter = intent.getStringExtra("chapter");
                        this.title = intent.getStringExtra("title");
                        playVoice(text);
                        break;
                    case ACTION_STOP:
                        stopTTS();
                        break;
                    case ACTION_CHANGE_SPEED:
                        if (mTTS != null) {
                            float speed = intent.getFloatExtra("speed", 1.0f);
                            mTTS.setSpeechRate(speed);
                        }
                        break;


                }
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

    private void initTTSAndPlay() {
        if (mTTS == null) {
            mTTS = new TextToSpeech(this, new TTSListener());
            mTTS.setSpeechRate(ReadSettingManager.getInstance().getTTSSpeed());
        }
    }
    public static void play(Context context, String title, String icon, String chapter, String text) {
        Intent intent = new Intent(context, VoiceService.class);
        intent.setAction(ACTION_START);
        intent.putExtra("title", title);
        intent.putExtra("icon", icon);
        intent.putExtra("chapter", chapter);
        intent.putExtra("text", text);
        context.startService(intent);
    }

    public static void stop(Context context) {
        if (running) {
            Intent intent = new Intent(context, VoiceService.class);
            intent.setAction(ACTION_STOP);
            context.startService(intent);
        }
    }

    public static void pause(Context context) {
        if (running) {
            Intent intent = new Intent(context, VoiceService.class);
            intent.setAction(ACTION_PAUSE);
            context.startService(intent);
        }
    }

    public static void resume(Context context) {
        if (running) {
            Intent intent = new Intent(context, VoiceService.class);
            intent.setAction(VoiceService.ACTION_RESUME);
            context.startService(intent);
        }
    }

    public static void changeSpeed(Context context, float speed) {
        if (running) {
            Intent intent = new Intent(context, VoiceService.class);
            intent.setAction(VoiceService.ACTION_CHANGE_SPEED);
            intent.putExtra("speed", speed);
            context.startService(intent);
        }
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new InnerBinder();
    }

    private void unRegisterMediaButton() {
        if (mediaSessionCompat != null) {
            mediaSessionCompat.setCallback(null);
            mediaSessionCompat.setActive(false);
            mediaSessionCompat.release();
        }
        audioManager.abandonAudioFocus(audioFocusChangeListener);
    }

    public void playVoice(String text) {
        if (running) {
            updateNotification();
            if (!ttsInitedSuccess) {
                initTTSAndPlay();
            } else {
                playTTS();
            }
        }
    }


    private void playTTS() {
        if (ttsInitedSuccess && requestFocus()) {
            HashMap<String, String> map = new HashMap<>();
            map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "whiteape");
            if (mTTS != null) {
                mTTS.speak(text, TextToSpeech.QUEUE_FLUSH, map);
            } else {
                initTTSAndPlay();
            }
        }

    }
    /**
     * @param pause true 暂停, false 失去焦点
     * @param pause
     */
    public void pauseVoice(boolean pause) {
        if (running) {
            this.pause = pause;
            speak = false;
            updateNotification();
            updateMediaSessionPlaybackState();
            if (mTTS != null && mTTS.isSpeaking()) {
                mTTS.stop();
            }
        }

    }

    public void resumeVoice() {
        if (running) {
            this.pause = false;
            updateNotification();
            playVoice(text);

        }
//        if (running) {
//            Intent intent = new Intent(context, ReadAloudService.class);
//            intent.setAction(ActionResumeService);
//            context.startService(intent);
//        }
    }

    public void stopTTS() {
        RxBus.get().post(RxEvent.VOICE_TTS_STOP, "whiteape");
        stopSelf();
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    private void initFocusRequest() {
        AudioAttributes mPlaybackAttributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build();
        mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
                .setAudioAttributes(mPlaybackAttributes)
                .setAcceptsDelayedFocusGain(true)
                .setOnAudioFocusChangeListener(audioFocusChangeListener)
                .build();
    }

    private PendingIntent getReadBookActivityPendingIntent() {
        Intent intent = new Intent(this, BookReadActivity.class);
        intent.setAction(ACTION_OPEN_READ_ACTIVITY);
        return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    private PendingIntent getThisServicePendingIntent(String actionStr) {
        Intent intent = new Intent(this, this.getClass());
        intent.setAction(actionStr);
        return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    private void updateNotification() {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, WaApp.NOTIFICATION_CHANNEL_DEFAULT)
                .setSmallIcon(R.drawable.ic_volume_up)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_app))
                .setOngoing(true)
                .setContentTitle(title)
                .setContentText(chapter)
                .setContentIntent(getReadBookActivityPendingIntent());
        if (pause) {
            builder.addAction(R.drawable.ic_play_24dp, "恢复", getThisServicePendingIntent(ACTION_RESUME));
        } else {
            builder.addAction(R.drawable.ic_pause_24dp, "暂停", getThisServicePendingIntent(ACTION_PAUSE));
        }
        builder.addAction(R.drawable.ic_stop_black_24dp, "停止", getThisServicePendingIntent(ACTION_STOP));
//        builder.addAction(R.drawable.ic_time_add_24dp, getString(R.string.set_timer), getThisServicePendingIntent(ActionSetTimer));
        builder.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
                .setMediaSession(mediaSessionCompat.getSessionToken())
                .setShowActionsInCompactView(0, 1));
        builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
        Notification notification = builder.build();

        startForeground(notificationId, notification);

//        NotificationTarget notificationTarget = new NotificationTarget(this, androidx.core.R.id.right_icon,builder.getContentView(),  )

    }

    /**
     * @return 音频焦点
     */
    private boolean requestFocus() {
        if (!isAudio) {
            MediaManager.playSilentSound(this);
        }
        int request;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            request = audioManager.requestAudioFocus(mFocusRequest);
        } else {
            request = audioManager.requestAudioFocus(audioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        }
        return (request == AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
    }

    private void updateMediaSessionPlaybackState() {
        //TODO setState 的position?
        mediaSessionCompat.setPlaybackState(
                new PlaybackStateCompat.Builder()
                        .setActions(MEDIA_SESSION_ACTIONS)
                        .setState(speak ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED,
                                0, 1)
                        .build());
    }

    private void initTTSEvent() {
        mTTS.setOnUtteranceProgressListener(new UtteranceProgressListener() {
            @Override
            public void onStart(String utteranceId) {

            }

            @Override
            public void onDone(String utteranceId) {
//                mPageLoader.reDrawCurPage(false);
//                mPageLoader.onTTSDone();
                RxBus.get().post(RxEvent.VOICE_TTS_DONE, utteranceId);

            }

            @Override
            public void onError(String utteranceId) {
                ToastUtils.show("语音播报出现错误");
            }
        });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        RxBus.get().unregister(this);
        stopForeground(true);
        unRegisterMediaButton();
        if (mTTS != null) {
            mTTS.stop();
            mTTS.shutdown();
            mTTS = null;
        }
        unregisterReceiver(broadcastReceiver);
    }

    private class InnerBinder extends Binder {
        public VoiceService getService() {
            return VoiceService.this;
        }
    }

    public void jumpToTTSSetting() {
        //跳转到文字转语音设置界面
        try {
            Intent intent = new Intent();
            intent.setAction("com.android.settings.TTS_SETTINGS");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        } catch (Exception ignored) {
        }
    }

    /**
     * 初始化MediaSession
     */
    private void initMediaSession() {
        ComponentName mComponent = new ComponentName(getPackageName(), MediaButtonIntentReceiver.class.getName());
        Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
        mediaButtonIntent.setComponent(mComponent);
        PendingIntent mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(this, 0,
                mediaButtonIntent, PendingIntent.FLAG_CANCEL_CURRENT);

        mediaSessionCompat = new MediaSessionCompat(this, TAG, mComponent, mediaButtonReceiverPendingIntent);
        mediaSessionCompat.setCallback(new MediaSessionCompat.Callback() {
            @Override
            public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
                return MediaButtonIntentReceiver.handleIntent(VoiceService.this, mediaButtonEvent);
            }
        });
        mediaSessionCompat.setMediaButtonReceiver(mediaButtonReceiverPendingIntent);
    }

    private void initBroadcastReceiver() {
        broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(action)) {
                    pauseVoice(true);
                }
            }
        };
        IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
        registerReceiver(broadcastReceiver, intentFilter);
    }

    class AudioFocusChangeListener implements AudioManager.OnAudioFocusChangeListener {
        @Override
        public void onAudioFocusChange(int focusChange) {
            switch (focusChange) {
                case AudioManager.AUDIOFOCUS_GAIN:
                    // 重新获得焦点,  可做恢复播放，恢复后台音量的操作
                    if (!pause) {
                        resumeVoice();
                    }
                    break;
                case AudioManager.AUDIOFOCUS_LOSS:
                    // 永久丢失焦点除非重新主动获取，这种情况是被其他播放器抢去了焦点，  为避免与其他播放器混音，可将音乐暂停
                    break;
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                    // 暂时丢失焦点，这种情况是被其他应用申请了短暂的焦点，可压低后台音量
                    if (!pause) {
                        pauseVoice(false);
                    }
                    break;
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                    // 短暂丢失焦点，这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量（或者关闭声音）凸显这个声音（比如短信提示音），
                    break;
            }
        }
    }

    private class TTSListener implements TextToSpeech.OnInitListener {
        @Override
        public void onInit(int status) {
            if (status == TextToSpeech.SUCCESS) {
                int supported = mTTS.setLanguage(Locale.SIMPLIFIED_CHINESE);
                if ((supported != TextToSpeech.LANG_AVAILABLE) && (supported != TextToSpeech.LANG_COUNTRY_AVAILABLE)) {
                    ToastUtils.show("当前系统不支持中文TTS,请先去设置");
                    stopTTS();
                    jumpToTTSSetting();
                } else {
                    initTTSEvent();
                    ttsInitedSuccess = true;
                    playTTS();

                }

            }else {
                ToastUtils.show("系统不支持TTS");
                stopTTS();
            }

        }
    }
}
